﻿Imports System.Linq.Expressions
Imports System.Reflection
Imports Kairyu.DCEngine

''' <summary>
''' クエリプロバイダー
''' </summary>
''' <remarks></remarks>
Public Class QueryProvider

    ''' <summary>
    ''' コンストラクタ
    ''' </summary>
    ''' <param name="loader">ローダー</param>
    ''' <remarks></remarks>
    Public Sub New(loader As Loader)
        Me.Loader = loader
    End Sub

    Private _loader As Loader
    ''' <summary>
    ''' ローダー
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property Loader() As Loader
        Get
            Return _loader
        End Get
        Friend Set(ByVal value As Loader)
            _loader = value
        End Set
    End Property

    ''' <summary>
    ''' 結果を格納するリストを生成します
    ''' </summary>
    ''' <param name="listType"></param>
    ''' <returns></returns>
    ''' <remarks>ジェネリックリストを生成します</remarks>
    Protected Overridable Function CreateListInstance(listType As Type) As IList
        Dim gt As Type = listType.ToListGenericType
        Dim lst = Activator.CreateInstance(gt)
        Return lst
    End Function

    ''' <summary>
    ''' クエリを実行します
    ''' </summary>
    ''' <param name="query"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function Execute(query As IQuery) As IList
        If query Is Nothing Then Throw New ArgumentNullException("query")

        Dim root As Type = query.RootType

        Dim rootMap = (New TableMapFactory).Create(root, query)

        Dim lst As IList = Me.CreateListInstance(root)

        'DBコマンド
        Using cmd As IDbCommand = Me.Loader.BuildSelectCommand(rootMap)
            Dim rows As Integer = 0
            Using r As IDataReader = cmd.Logging.ExecuteReader
                While r.Read()
                    'マッピング
                    Dim c = rootMap.ToEntity(r)
                    lst.Add(c)
                    rows += 1
                End While
            End Using
        End Using

        'LowerPropertyをインスタンスする
        For Each lowerProp In root.ToEntityDefinition.LowerProperties
            For Each current In lst
                Dim loadableList = LoadableListActivator.Activate(current, lowerProp, Me.Loader)
                lowerProp.SetValue(current, loadableList, Nothing)
            Next
        Next

        Return lst
    End Function
End Class